/** 数组比较 */

/**
 * @description 平等比较
 * @description JavaScript 中数组和对象通过引用而不是通过值进行比较，故平等比较为 false。
 */
const a = [1, 2, 3];
const b = [1, 2, 3];
a === b; // false

/**
 * @description JSON.stringify
 * @description JSON.stringify()，它允许我们序列化每个数组，然后比较两个序列化的字符串。在某些不同值的序列化字符串相同的边缘情况下存在缺陷。
 */
const equals = (a, b) => JSON.stringify(a) === JSON.stringify(b);
const a = [1, 2, 3];
const b = [1, 2, 3];
equals(a, b); // true

// 边界条件
const str = "a";
const strObj = new String("a");
str === strObj; // false
equals([str], [strObj]); // true, should be false

null === undefined; // false
equals([null], [undefined]); // true, should be false

/**
 * @description Array.prototype.every() 和 Array.length
 * @description 数组顺序时
 */
const equalsOrder = (a, b) =>
  a.length === b.length && a.every((v, i) => v === b[i]);

const a = [1, 2, 3];
const b = [1, 2, 3];
const str = "a";
const strObj = new String("a");

// 边界条件正确
equalsOrder(a, b); // true
equalsOrder([str], [strObj]); // false
equalsOrder([null], [undefined]); // false

// 当考虑需要递归检查的嵌套数组或对象。对于处理此问题和其他问题的强大解决方案：
const equalsOrder2 = (a, b) => {
  if (a === b) return true;
  if (a instanceof Date && b instanceof Date)
    return a.getTime() === b.getTime();
  if (!a || !b || (typeof a !== 'object' && typeof b !== 'object'))
    return a === b;
  if (a.prototype !== b.prototype) return false;
  let keys = Object.keys(a);
  if (keys.length !== Object.keys(b).length) return false;
  return keys.every(k => equals(a[k], b[k]));
};


/**
 * @description Set 和 Array.prototype.filter()
 * @description 数组乱序时
 */
const equalsIgnoreOrder = (a, b) => {
  if (a.length !== b.length) return false;
  const uniqueValues = new Set([...a, ...b]);
  for (const v of uniqueValues) {
    const aCount = a.filter((e) => e === v).length;
    const bCount = b.filter((e) => e === v).length;
    if (aCount !== bCount) return false;
  }
  return true;
};
